package dnspod

import (
	"fmt"
	"net/url"
	"strconv"

	"github.com/antonholmquist/jason"
)

// Record record
type Record struct {
	ID    int    `json:"id"`
	Name  string `json:"name"`
	Type  string `json:"type"`
	Value string `json:"value"`
}

func getRecord(obj *jason.Object) Record {
	id := getID(obj)
	name, err := obj.GetString("name")
	assert(err)
	t, err := obj.GetString("type")
	assert(err)
	value, err := obj.GetString("value")
	assert(err)
	return Record{
		ID:    id,
		Name:  name,
		Type:  t,
		Value: value,
	}
}

// RecordList list all records
func (c Client) RecordList(domain, keyword string) (Domain, []Record, error) {
	params := make(url.Values)
	params.Set("domain", domain)
	if len(keyword) > 0 {
		params.Set("keyword", keyword)
	}
	var dm Domain
	var ret []Record
	err := c.list("Record.List", params, func(obj *jason.Object) (int, bool) {
		code, err := obj.GetString("status", "code")
		assert(err)
		if code == "10" { // No records
			return 0, false
		}
		// status
		checkResponseCode(obj, "Record.List", true)

		// get domain info
		dmObj, err := obj.GetObject("domain")
		assert(err)
		dm = getDomain(dmObj)

		// get record list
		var cnt int
		records, err := obj.GetObjectArray("records")
		assert(err)
		for _, record := range records {
			ret = append(ret, getRecord(record))
			cnt++
		}

		// want next
		rt, err := obj.GetString("info", "record_total")
		assert(err)
		all, err := strconv.ParseInt(rt, 10, 64)
		assert(err)
		if len(ret) >= int(all) {
			return cnt, false
		}
		return cnt, true
	})
	if err != nil {
		return dm, nil, err
	}
	return dm, ret, nil
}

// AddRecord add record
func (c Client) AddRecord(domain, record, recordType, value string) (int, error) {
	// make params
	params := make(url.Values)
	params.Set("domain", domain)
	params.Set("sub_domain", record)
	params.Set("record_type", recordType)
	params.Set("value", value)
	params.Set("record_line", "默认")

	// request
	resp, err := c.request("Record.Create", params)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()

	// decode
	obj, err := jason.NewObjectFromReader(resp.Body)
	if err != nil {
		return 0, err
	}

	// status
	err = checkResponseCode(obj, "Record.Create", false)
	if err != nil {
		return 0, err
	}

	// get id
	rid, err := obj.GetString("record", "id")
	if err != nil {
		return 0, err
	}

	id, err := strconv.ParseInt(rid, 10, 64)
	if err != nil {
		return 0, err
	}
	return int(id), nil
}

// UpdateRecord update record
func (c Client) UpdateRecord(id int, domain, record, recordType, value string) (int, error) {
	// make params
	params := make(url.Values)
	params.Set("domain", domain)
	params.Set("record_id", fmt.Sprintf("%d", id))
	params.Set("sub_domain", record)
	params.Set("record_type", recordType)
	params.Set("value", value)
	params.Set("record_line", "默认")

	// request
	resp, err := c.request("Record.Modify", params)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()

	// decode
	obj, err := jason.NewObjectFromReader(resp.Body)
	if err != nil {
		return 0, err
	}

	// status
	err = checkResponseCode(obj, "Record.Modify", false)
	if err != nil {
		return 0, err
	}

	// get id
	rid, err := obj.GetInt64("record", "id")
	if err != nil {
		return 0, err
	}
	return int(rid), nil
}

// RemoveRecord remove record
func (c Client) RemoveRecord(id int, domain string) error {
	// make params
	params := make(url.Values)
	params.Set("domain", domain)
	params.Set("record_id", fmt.Sprintf("%d", id))

	// request
	resp, err := c.request("Record.Remove", params)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// decode
	obj, err := jason.NewObjectFromReader(resp.Body)
	if err != nil {
		return err
	}

	// status
	err = checkResponseCode(obj, "Record.Remove", false)
	if err != nil {
		return err
	}

	return nil
}
